#include "DirectXEngine.h"

CDirectXEngine * CDirectXEngine::instance = NULL;

CDirectXEngine::CDirectXEngine(void)
{
	windowX = 800;
	windowY = 600;
}

CDirectXEngine * CDirectXEngine::Instance()
{
	//TODO: put an assert here to check that engine is created when we expect it to be
	if (instance == NULL)
	{		
		instance = new CDirectXEngine();
	}

	return instance;
}

CDirectXEngine::~CDirectXEngine(void)
{

}

void CDirectXEngine::Initialise(HWND hWnd, int winX, int winY)
{
	windowHandle = hWnd;

	windowX = winX;
	windowY = winY;

    d3d = Direct3DCreate9(D3D_SDK_VERSION);

    D3DPRESENT_PARAMETERS d3dpp;

    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.Windowed = TRUE;
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.hDeviceWindow = hWnd;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferWidth = windowX;
    d3dpp.BackBufferHeight = windowY;
    d3dpp.EnableAutoDepthStencil = TRUE;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D16;

    // create a device class using this information and the info from the d3dpp stuct
    d3d->CreateDevice(D3DADAPTER_DEFAULT,
                      D3DDEVTYPE_HAL,
                      hWnd,
                      D3DCREATE_SOFTWARE_VERTEXPROCESSING,
                      &d3dpp,
                      &d3ddev);

    d3ddev->SetRenderState(D3DRS_LIGHTING, TRUE);    // turn on the 3D lighting
	d3ddev->SetRenderState(D3DRS_AMBIENT, D3DCOLOR_XRGB(200, 200, 200));    // ambient light
    d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE);    // turn on the z-buffer

	//d3ddev->SetRenderState(D3DRS_POINTSPRITEENABLE,true);
	//d3ddev->SetRenderState(D3DRS_POINTSCALEENABLE,false);
	//d3ddev->SetRenderState(D3DRS_POINTSIZE,10.0);
	//d3ddev->SetRenderState(D3DRS_POINTSCALE_B, 10.0);

	//Light set up 
	//TODO: should be in a lighting entity
	D3DLIGHT9 light;    // create the light struct

    ZeroMemory(&light, sizeof(light));    // clear out the struct for use
    light.Type = D3DLIGHT_DIRECTIONAL;    // make the light type 'directional light'
    light.Diffuse.r = 0.5f;    // .5 red
    light.Diffuse.g = 0.5f;    // .5 green
    light.Diffuse.b = 0.5f;    // .5 blue
    light.Diffuse.a = 1.0f;    // full alpha (we'll get to that soon)

    D3DVECTOR vecDirection = {-1.0f, -0.3f, -1.0f};    // the direction of the light

    light.Direction = vecDirection;    // set the direction

	D3DVECTOR vecPosition = {0.0f, 5.0f, 2.0f};  
	light.Position = vecPosition;

    d3ddev->SetLight(0, &light);    // send the light struct properties to light #0
    d3ddev->LightEnable(0, TRUE);    // turn on light #0

}


void CDirectXEngine::Clean()
{
	d3ddev->Release();    // close and release the 3D device
    d3d->Release();    // close and release Direct3D
}

void CDirectXEngine::BeginScene()
{
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
    d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);

    d3ddev->BeginScene();    // begins the 3D scene

	//TODO: this may not be the best way to set up the projection but it seems to work
	// set the projection transform
    D3DXMATRIX matProjection;    // the projection transform matrix
    D3DXMatrixPerspectiveFovLH(&matProjection,
                               D3DXToRadian(45),    // the horizontal field of view
                               (FLOAT)windowX / (FLOAT)windowY, // aspect ratio
                               1.0f,   // the near view-plane
                               100.0f);    // the far view-plane
    d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection

}

void CDirectXEngine::EndScene()
{
	d3ddev->EndScene();    // ends the 3D scene

	d3ddev->Present(NULL, NULL, NULL, NULL);   // displays the created frame on the screen
}